/**
 * \file Value.h
 * \brief Headers for known value Expression subclasses
 * \author Wouter Caarls <w.caarls@tnw.tudelft.nl> 
 *
 * \verbatim
 * Copyright (c) 2005 Wouter Caarls, Delft University of Technology
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * \endverbatim
 */

#ifndef __VALUE_H_INCLUDED
#define __VALUE_H_INCLUDED

#include "CStr.h"
#include "Type.h"
#include "Base.h"

class Compound;

class VoidValue : public Value
{
  public:
    VoidValue(Stat *_assignment=NULL, Declaration2 *_declaration=NULL) :
      Value(&BasicVoid, _assignment, _declaration) { known = false; }

    VoidValue(std::vector<Stat*> &_assignments, std::vector<Declaration2*> &_declarations) :
      Value(&BasicVoid, _assignments, _declarations) { known = false; }

    VoidValue *copy()
    {
      return new VoidValue(assignments, declarations);
    }

    VoidValue* reduce(SymbolTable *symbols, Compound *out, Use use=NotUsed);

    std::string toString(int indentation=0);
    std::string toTerm();
    int castToInteger() const;
    double castToFloat() const;
    void outputKnownValues(LeftExpression* base, Compound *out) { }
};

class IntegerValue : public Value
{
  public:
    IntegerValue() : Value(&BasicInteger), data(0) { known = false; }
    IntegerValue(int _data, Stat *_assignment=NULL, Declaration2 *_declaration=NULL) :
      Value(&BasicInteger, _assignment, _declaration), data(_data) {}
    IntegerValue(int _data, std::vector<Stat *> &_assignments, std::vector<Declaration2*> &_declarations) :
      Value(&BasicInteger, _assignments, _declarations), data(_data) {}

    IntegerValue *copy()
    {
      IntegerValue *res = new IntegerValue(data, assignments, declarations);
      res->known = known;
      
      return res;
    }

    IntegerValue* reduce(SymbolTable *symbols, Compound *out, Use use=NotUsed);
    std::string toString(int indentation=0);
    std::string toTerm();
    int castToInteger() const;
    double castToFloat() const;
    void outputKnownValues(LeftExpression* base, Compound *out);
  public:
    int data;
};

class FloatValue : public Value
{
  public:
    FloatValue() : Value(&BasicFloat), data(0) { known = false; }
    FloatValue(double _data, Stat *_assignment=NULL, Declaration2 *_declaration=NULL) :
      Value(&BasicFloat, _assignment, _declaration), data(_data) {}
    FloatValue(double _data, std::vector<Stat*> &_assignments, std::vector<Declaration2*> &_declarations) :
      Value(&BasicFloat, _assignments, _declarations), data(_data) {}

    FloatValue *copy()
    {
      FloatValue *res = new FloatValue(data, assignments, declarations);
      res->known = known;
      
      return res;
    }

    FloatValue* reduce(SymbolTable *symbols, Compound *out, Use use=NotUsed);
    std::string toString(int indentation=0);
    std::string toTerm();
    int castToInteger() const;
    double castToFloat() const;
    void outputKnownValues(LeftExpression* base, Compound *out);
  public:
    double data;
};

typedef struct ptr_to_s
{
  int index;
  LeftExpression* route;
} ptr_to_t;

class PointerValue : public Value
{
  public:
    typedef std::vector<ptr_to_t>::iterator TI;

    PointerValue();
    PointerValue(SymbolTable *symbols, int _index, LeftExpression *_route);
    PointerValue(Type *_type, int _index, LeftExpression *_route, Stat *_assignment=NULL,
		 Declaration2 *_declaration=NULL) :
      Value(_type, _assignment, _declaration)
      {
	LOG(plog.debug, HDR << "creating pointer " << this << " at index " << _index
		     << std::endl);       

	ptr_to_t _to;
	_to.index = _index;
	_to.route = _route;

	to.push_back(_to);
      }

    PointerValue(Type *_type, std::vector<ptr_to_t> &_to, std::vector<Stat*> &_assignments,
		 std::vector<Declaration2*> &_declarations) :
      Value(_type, _assignments, _declarations)
      {
	LOG(plog.debug, HDR << "creating pointer " << this << std::endl);

	for (TI ti=_to.begin(); ti != _to.end(); ++ti)
	{
	  ptr_to_t newto;
	  newto.index = ti->index;
	  newto.route = ti->route->copy();
	  to.push_back(newto);
	}
      }

    PointerValue *copy();

    Value* reduce(SymbolTable *symbols, Compound *out, Use use=NotUsed);
    void residualize(SymbolTable *symbols, bool markUnknown);
    bool dirtyChanged(SymbolTable *symbols, Value *rhs, bool mergeAssignments);

    std::string toString(int indentation=0);
    std::string toTerm();
    int castToInteger() const;
    double castToFloat() const;
    void outputKnownValues(LeftExpression* base, Compound *out) { }

    bool storageIsKnown(SymbolTable *symbols, Compound *out, bool useValue);
  public:
    std::vector<ptr_to_t> to;
};

class ArrayValue : public Value
{
  public:
    typedef std::vector<Value**>::iterator EI;

    ArrayValue() : Value(&NullPointer) { known = false; }
    ArrayValue(Type *_type, Stat *_assignment=NULL, Declaration2 *_declaration=NULL) :
      Value(_type, _assignment, _declaration) {}
    ArrayValue(Type *_type, std::vector<Stat*> &_assignments, std::vector<Declaration2*> &_declarations) :
      Value(_type, _assignments, _declarations) {}
    ArrayValue(Type *_type, Value *_data, int _elements) : Value(_type)
    {
      for (int i=0; i < _elements; ++i)
	data.push_back(new Value*(_data->copy()));

      delete _data;
    }

    ~ArrayValue()
    {
      for (EI ii = data.begin(); ii != data.end(); ++ii)
      {
	delete (**ii);
	delete (*ii);
      }
    }

    ArrayValue *copy();
    ArrayValue* reduce(SymbolTable *symbols, Compound *out, Use use=NotUsed);
    void residualize(SymbolTable *symbols, bool markUnknown);
    void removeGenerators();
    bool dirtyChanged(SymbolTable *symbols, Value *rhs, bool mergeAssignments);

    std::string toString(int indentation=0);
    std::string toTerm();
    int castToInteger() const;
    double castToFloat() const;
    void outputKnownValues(LeftExpression* base, Compound *out);

    bool storageIsKnown(SymbolTable *symbols, Compound *out, bool useValue);
  public:
    std::vector<Value**> data;
};

class StructValue : public Value
{
  public:
    typedef std::vector<Value**>::iterator EI;

    StructValue() : Value(&NullPointer) { known = false; }
    StructValue(Type *_type, Stat *_assignment=NULL, Declaration2 *_declaration=NULL) :
      Value(_type, _assignment, _declaration) {}
    StructValue(Type *_type, std::vector<Stat*> &_assignments, std::vector<Declaration2*> &_declarations) :
      Value(_type, _assignments, _declarations) {}

    ~StructValue()
    {
      for (EI ii = data.begin(); ii != data.end(); ++ii)
      {
	delete (**ii);
	delete (*ii);
      }
    }

    StructValue *copy();
    StructValue *reduce(SymbolTable *symbols, Compound *out, Use use=NotUsed);
    void residualize(SymbolTable *symbols, bool markUnknown);
    virtual void removeGenerators();
    bool dirtyChanged(SymbolTable *symbols, Value *rhs, bool mergeAssignments);

    std::string toString(int indentation=0);
    std::string toTerm();
    int castToInteger() const;
    double castToFloat() const;
    void outputKnownValues(LeftExpression*, Compound *out);

    void push_back(Value **element)
    {
      data.push_back(element);
    }

    bool storageIsKnown(SymbolTable *symbols, Compound *out, bool useValue);
  public:
    std::vector<Value**> data;
};

class CodeValue : public Value
{
  public:
    CodeValue() : Value(&BasicCode), data(NULL) { known = false; }
    CodeValue(Code *_data, Stat *_assignment=NULL, Declaration2 *_declaration=NULL) :
      Value(&BasicCode, _assignment, _declaration), data(_data) {}
    CodeValue(Code *_data, std::vector<Stat*> &_assignments, std::vector<Declaration2*> &_declarations) :
      Value(&BasicCode, _assignments, _declarations), data(_data) {}

    ~CodeValue()
    {
      delete data;
    }


    CodeValue *copy()
    {
      CodeValue *res;

      if (data)
	res = new CodeValue(data->copy(), assignments, declarations);
      else
	res = new CodeValue(data, assignments, declarations);

      res->known = known;

      return res;
    }

    Expression* reduce(SymbolTable *symbols, Compound *out, Use use=NotUsed);
    std::string toString(int indentation=0);
    std::string toTerm();
    int castToInteger() const;
    double castToFloat() const;
    void outputKnownValues(LeftExpression*, Compound *out);

    CodeValue *replace(Code *src, Code *rplc,
			  SymbolTable *symbols, Compound *out)
    {
      return new CodeValue(data->replace(src, rplc, symbols, out));
    }

  public:
    Code *data;
};

#endif /* __VALUE_H_INCLUDED */
